home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / bash-1.12 / dist / RCS / test.c,v < prev   
Encoding:
Text File  |  1992-12-15  |  23.0 KB  |  1,087 lines

  1. head     1.2;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.2
  10. date     92.12.15.11.18.00;  author jhh;  state Exp;
  11. branches ;
  12. next     1.1;
  13.  
  14. 1.1
  15. date     92.12.15.10.46.01;  author jhh;  state Exp;
  16. branches ;
  17. next     ;
  18.  
  19.  
  20. desc
  21. @@
  22.  
  23.  
  24. 1.2
  25. log
  26. @sprite has gid_t
  27. @
  28. text
  29. @/* GNU test program (ksb and mjb) */
  30.  
  31. /* Modified to run with the GNU shell Apr 25, 1988 by bfox. */
  32.  
  33. /* Copyright (C) 1987, 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
  34.  
  35.    This file is part of GNU Bash, the Bourne Again SHell.
  36.  
  37.    Bash is free software; you can redistribute it and/or modify it under
  38.    the terms of the GNU General Public License as published by the Free
  39.    Software Foundation; either version 2, or (at your option) any later
  40.    version.
  41.  
  42.    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  43.    WARRANTY; without even the implied warranty of MERCHANTABILITY or
  44.    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  45.    for more details.
  46.  
  47.    You should have received a copy of the GNU General Public License along
  48.    with Bash; see the file COPYING.  If not, write to the Free Software
  49.    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  50.  
  51. /* Define STANDALONE to get the /bin/test version.  Otherwise, you get 
  52.    the shell builtin version. */
  53. /* #define STANDALONE */
  54.  
  55. #include <stdio.h>
  56. #include <sys/types.h>
  57.  
  58. #if defined (STANDALONE)
  59. #  if defined (HAVE_UNISTD_H)
  60. #    include <unistd.h>
  61. #  endif /* HAVE_UNISTD_H */
  62. #else /* !STANDALONE */
  63. #  include "shell.h"
  64. #endif /* !STANDALONE */
  65.  
  66. #if !defined (_POSIX_VERSION)
  67. #  include <sys/file.h>
  68. #endif /* !_POSIX_VERSION */
  69.  
  70. #include <errno.h>
  71. #if !defined (errno)
  72. extern int errno;
  73. #endif /* !errno */
  74.  
  75. #if !defined (STANDALONE)
  76. #  include "posixstat.h"
  77. #  include "filecntl.h"
  78. #else /* STANDALONE */
  79. #  include "system.h"
  80. #  if !defined (S_IXUGO)
  81. #    define S_IXUGO 0111
  82. #  endif
  83. #endif /* STANDALONE */
  84.  
  85. #if !defined (STREQ)
  86. #  define STREQ(a, b) ((a)[0] == (b)[0] && strcmp (a, b) == 0)
  87. #endif /* !STREQ */
  88.  
  89. #if !defined (member)
  90. #  define member(c, s) (int)((c) ? index ((s), (c)) : 0)
  91. #endif /* !member */
  92.  
  93. #if defined (STANDALONE) && (defined (USG) || defined (STDC_HEADERS))
  94. #  if !defined (index)
  95. #    define index strchr
  96. #    define rindex strrchr
  97. #  endif /* !index */
  98. #endif /* STANDALONE && (USG || STDC_HEADERS) */
  99.  
  100. /* Make gid_t and uid_t mean something for non-posix systems. */
  101. #if !defined (_POSIX_VERSION) && !defined(sprite)
  102. #  if !defined (gid_t)
  103. #    define gid_t int
  104. #  endif
  105. #  if !defined (uid_t)
  106. #    define uid_t int
  107. #  endif
  108. #endif /* !_POSIX_VERSION */
  109.  
  110. extern gid_t getgid (), getegid ();
  111. extern uid_t geteuid ();
  112.  
  113. #if !defined (R_OK)
  114. #define R_OK 4
  115. #define W_OK 2
  116. #define X_OK 1
  117. #define F_OK 0
  118. #endif /* R_OK */
  119.  
  120. /* The following few defines control the truth and false output of each stage.
  121.    TRUE and FALSE are what we use to compute the final output value.
  122.    SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
  123.    TRUTH_OR is how to do logical or with TRUE and FALSE.
  124.    TRUTH_AND is how to do logical and with TRUE and FALSE..
  125.    Default is TRUE = 1, FALSE = 0, TRUTH_OR = a | b, TRUTH_AND = a & b,
  126.     SHELL_BOOLEAN = (!value). */
  127. #define TRUE 1
  128. #define FALSE 0
  129. #define SHELL_BOOLEAN(value) (!(value))
  130. #define TRUTH_OR(a, b) ((a) | (b))
  131. #define TRUTH_AND(a, b) ((a) & (b))
  132.  
  133. #if defined (STANDALONE)
  134. #  define test_exit(val) exit (val)
  135. #else
  136.    static jmp_buf test_exit_buf;
  137.    static int test_error_return = 0;
  138. #  define test_exit(val) test_error_return = val, longjmp (test_exit_buf, 1)
  139. #endif /* STANDALONE */
  140.  
  141. static int pos;        /* The offset of the current argument in ARGV. */
  142. static int argc;    /* The number of arguments present in ARGV. */
  143. static char **argv;    /* The argument list. */
  144.  
  145. static int unop ();
  146. static int binop ();
  147. static int unary_operator ();
  148. static int binary_operator ();
  149. static int two_arguments ();
  150. static int three_arguments ();
  151. static int posixtest ();
  152.  
  153. static int expr ();
  154. static int term ();
  155. static int and ();
  156. static int or ();
  157.  
  158. static void
  159. test_syntax_error (format, arg)
  160.      char *format, *arg;
  161. {
  162.   fprintf (stderr, "%s: ", argv[0]);
  163.   fprintf (stderr, format, arg);
  164.   fflush (stderr);
  165.   test_exit (SHELL_BOOLEAN (FALSE));
  166. }
  167.  
  168. /* A wrapper for stat () which disallows pathnames that are empty strings. */
  169. static int
  170. test_stat (path, finfo)
  171.      char *path;
  172.      struct stat *finfo;
  173. {
  174.   if (*path == '\0')
  175.     {
  176.       errno = ENOENT;
  177.       return (-1);
  178.     }
  179.   return (stat (path, finfo));
  180. }
  181.  
  182. /* Do the same thing access(2) does, but use the effective uid and gid,
  183.    and don't make the mistake of telling root that any file is
  184.    executable. */
  185. static int
  186. eaccess (path, mode)
  187.      char *path;
  188.      int mode;
  189. {
  190.   extern int group_member ();
  191.   struct stat st;
  192.   static int euid = -1;
  193.  
  194.   if (test_stat (path, &st) < 0)
  195.     return (-1);
  196.  
  197.   if (euid == -1)
  198.     euid = geteuid ();
  199.  
  200.   if (euid == 0)
  201.     {
  202.       /* Root can read or write any file. */
  203.       if (mode != X_OK)
  204.     return (0);
  205.  
  206.       /* Root can execute any file that has any one of the execute
  207.      bits set. */
  208.       if (st.st_mode & S_IXUGO)
  209.     return (0);
  210.     }
  211.  
  212.   if (st.st_uid == euid)        /* owner */
  213.     mode <<= 6;
  214.   else if (group_member (st.st_gid))
  215.     mode <<= 3;
  216.  
  217.   if (st.st_mode & mode)
  218.     return (0);
  219.  
  220.   return (-1);
  221. }
  222.  
  223. #if defined (HAVE_GETGROUPS)
  224. /* The number of groups that this user is a member of. */
  225. static int ngroups = 0;
  226. static gid_t *group_array = (gid_t *)NULL;
  227. static int default_group_array_size = 0;
  228. #endif /* HAVE_GETGROUPS */
  229.  
  230. /* Return non-zero if GID is one that we have in our groups list. */
  231. int
  232. group_member (gid)
  233.      gid_t gid;
  234. {
  235. #if !defined (HAVE_GETGROUPS)
  236.   return ((gid == getgid ()) || (gid == getegid ()));
  237. #else
  238.   register int i;
  239.  
  240.   /* getgroups () returns the number of elements that it was able to
  241.      place into the array.  We simply continue to call getgroups ()
  242.      until the number of elements placed into the array is smaller than
  243.      the physical size of the array. */
  244.  
  245.   while (ngroups == default_group_array_size)
  246.     {
  247.       default_group_array_size += 64;
  248.  
  249.       group_array = (gid_t *)
  250.     xrealloc (group_array,
  251.           default_group_array_size * sizeof (gid_t));
  252.  
  253.       ngroups = getgroups (default_group_array_size, group_array);
  254.     }
  255.  
  256.   /* In case of error, the user loses. */
  257.   if (ngroups < 0)
  258.     return (0);
  259.  
  260.   /* Search through the list looking for GID. */
  261.   for (i = 0; i < ngroups; i++)
  262.     if (gid == group_array[i])
  263.       return (1);
  264.  
  265.   return (0);
  266. #endif /* HAVE_GETGROUPS */
  267. }
  268.  
  269. /* Increment our position in the argument list.  Check that we're not
  270.    past the end of the argument list.  This check is supressed if the
  271.    argument is FALSE.  Made a macro for efficiency. */
  272. #if !defined (lint)
  273. #define advance(f)    (++pos, f && (pos < argc ? 0 : beyond()))
  274. #endif
  275.  
  276. #if !defined (advance)
  277. static int
  278. advance (f)
  279.      int f;
  280. {
  281.   ++pos;
  282.  
  283.   if (f && pos >= argc)
  284.     beyond ();
  285. }
  286. #endif /* advance */
  287.  
  288. #define unary_advance() (advance (1),++pos)
  289.  
  290. /*
  291.  * beyond - call when we're beyond the end of the argument list (an
  292.  *    error condition)
  293.  */
  294. static int
  295. beyond ()
  296. {
  297.   test_syntax_error ("argument expected\n", (char *)NULL);
  298. }
  299.  
  300. /* Syntax error for when an integer argument was expected, but
  301.    something else was found. */
  302. static void
  303. integer_expected_error (pch)
  304.      char *pch;
  305. {
  306.   test_syntax_error ("integer expression expected %s\n", pch);
  307. }
  308.  
  309. /* Return non-zero if the characters pointed to by STRING constitute a
  310.    valid number.  Stuff the converted number into RESULT if RESULT is
  311.    a non-null pointer to a long. */
  312. static int
  313. isint (string, result)
  314.      register char *string;
  315.      long *result;
  316. {
  317.   int sign;
  318.   long value;
  319.  
  320.   sign = 1;
  321.   value = 0;
  322.  
  323.   if (result)
  324.     *result = 0;
  325.  
  326.   /* Skip leading whitespace characters. */
  327.   while (whitespace (*string))
  328.     string++;
  329.  
  330.   if (!*string)
  331.     return (0);
  332.  
  333.   /* We allow leading `-' or `+'. */
  334.   if (*string == '-' || *string == '+')
  335.     {
  336.       if (!digit (string[1]))
  337.     return (0);
  338.  
  339.       if (*string == '-')
  340.     sign = -1;
  341.  
  342.       string++;
  343.     }
  344.  
  345.   while (digit (*string))
  346.     {
  347.       if (result)
  348.     value = (value * 10) + digit_value (*string);
  349.       string++;
  350.     }
  351.  
  352.   /* Skip trailing whitespace, if any. */
  353.   while (whitespace (*string))
  354.     string++;
  355.  
  356.   /* Error if not at end of string. */
  357.   if (*string)
  358.     return (0);
  359.  
  360.   if (result)
  361.     {
  362.       value *= sign;
  363.       *result = value;
  364.     }
  365.  
  366.   return (1);
  367. }
  368.  
  369. /* Find the modification time of FILE, and stuff it into AGE, a pointer
  370.    to a long.  Return non-zero if successful, else zero. */
  371. static int
  372. age_of (filename, age)
  373.      char *filename;
  374.      long *age;
  375. {
  376.   struct stat finfo;
  377.  
  378.   if (test_stat (filename, &finfo) < 0)
  379.     return (0);
  380.  
  381.   if (age)
  382.     *age = finfo.st_mtime;
  383.  
  384.   return (1);
  385. }
  386.  
  387. /*
  388.  * term - parse a term and return 1 or 0 depending on whether the term
  389.  *    evaluates to true or false, respectively.
  390.  *
  391.  * term ::=
  392.  *    '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename
  393.  *    '-'('L'|'x') filename
  394.  *     '-t' [ int ]
  395.  *    '-'('z'|'n') string
  396.  *    string
  397.  *    string ('!='|'=') string
  398.  *    <int> '-'(eq|ne|le|lt|ge|gt) <int>
  399.  *    file '-'(nt|ot|ef) file
  400.  *    '(' <expr> ')'
  401.  * int ::=
  402.  *    '-l' string
  403.  *    positive and negative integers
  404.  */
  405. static int
  406. term ()
  407. {
  408.   int value;
  409.  
  410.   if (pos >= argc)
  411.     beyond ();
  412.  
  413.   /* Deal with leading "not"'s. */
  414.   if ('!' == argv[pos][0] && '\000' == argv[pos][1])
  415.     {
  416.       value = FALSE;
  417.       while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1])
  418.     {
  419.       advance (1);
  420.       value ^= (TRUE);
  421.     }
  422.  
  423.       return (value ^ (term ()));
  424.     }
  425.  
  426.   /* A paren-bracketed argument. */  
  427.   if (argv[pos][0] == '(' && !argv[pos][1])
  428.     {
  429.       advance (1);
  430.       value = expr ();
  431.       if (argv[pos][0] != ')' || argv[pos][1])
  432.     test_syntax_error ("')' expected, found %s\n", argv[pos]);
  433.       advance (0);
  434.       return (TRUE == (value));
  435.     }
  436.  
  437.   /* are there enough arguments left that this could be dyadic? */
  438.   if (((pos + 3 <= argc) && binop (argv[pos + 1])) ||
  439.       ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2]))))
  440.     value = binary_operator ();
  441.  
  442.   /* Might be a switch type argument */
  443.   else if ('-' == argv[pos][0] && 0 == argv[pos][2])
  444.     {
  445.       if (unop (argv[pos][1]))
  446.     value = unary_operator ();
  447.       else
  448.     test_syntax_error ("%s: unary operator expected\n", argv[pos]);
  449.     }
  450.   else
  451.     {
  452.       value = (argv[pos][0] != '\0');
  453.       advance (0);
  454.     }
  455.  
  456.   return (value);
  457. }
  458.  
  459. static int
  460. binary_operator ()
  461. {
  462.   register int op;
  463.   struct stat stat_buf, stat_spare;
  464.   long int l, r, value;
  465.   /* Are the left and right integer expressions of the form '-l string'? */
  466.   int l_is_l, r_is_l;
  467.  
  468.   if (strcmp (argv[pos], "-l") == 0)
  469.     {
  470.       l_is_l = 1;
  471.       op = pos + 2;
  472.  
  473.       /* Make sure that OP is still a valid binary operator. */
  474.       if ((op >= argc - 1) || (binop (argv[op]) == 0))
  475.     test_syntax_error ("%s: binary operator expected\n", argv[op]);
  476.  
  477.       advance (0);
  478.     }
  479.   else
  480.     {
  481.       l_is_l = 0;
  482.       op = pos + 1;
  483.     }
  484.  
  485.   if ((op < argc - 2) && (strcmp (argv[op + 1], "-l") == 0))
  486.     {
  487.       r_is_l = 1;
  488.       advance (0);
  489.     }
  490.   else
  491.     r_is_l = 0;
  492.  
  493.   if (argv[op][0] == '-')
  494.     {
  495.       /* check for eq, nt, and stuff */
  496.       switch (argv[op][1])
  497.     {
  498.     default:
  499.       break;
  500.  
  501.     case 'l':
  502.       if (argv[op][2] == 't' && !argv[op][3])
  503.         {
  504.           /* lt */
  505.           if (l_is_l)
  506.         l = strlen (argv[op - 1]);
  507.           else
  508.         {
  509.           if (!isint (argv[op - 1], &l))
  510.             integer_expected_error ("before -lt");
  511.         }
  512.  
  513.           if (r_is_l)
  514.         r = strlen (argv[op + 2]);
  515.           else
  516.         {
  517.           if (!isint (argv[op + 1], &r))
  518.             integer_expected_error ("after -lt");
  519.         }
  520.           pos += 3;
  521.           return (TRUE == (l < r));
  522.         }
  523.  
  524.       if (argv[op][2] == 'e' && !argv[op][3])
  525.         {
  526.           /* le */
  527.           if (l_is_l)
  528.         l = strlen (argv[op - 1]);
  529.           else
  530.         {
  531.           if (!isint (argv[op - 1], &l))
  532.             integer_expected_error ("before -le");
  533.         }
  534.           if (r_is_l)
  535.         r = strlen (argv[op + 2]);
  536.           else
  537.         {
  538.           if (!isint (argv[op + 1], &r))
  539.             integer_expected_error ("after -le");
  540.         }
  541.           pos += 3;
  542.           return (TRUE == (l <= r));
  543.         }
  544.       break;
  545.  
  546.     case 'g':
  547.       if (argv[op][2] == 't' && !argv[op][3])
  548.         {
  549.           /* gt integer greater than */
  550.           if (l_is_l)
  551.         l = strlen (argv[op - 1]);
  552.           else
  553.         {
  554.           if (!isint (argv[op - 1], &l))
  555.             integer_expected_error ("before -gt");
  556.         }
  557.           if (r_is_l)
  558.         r = strlen (argv[op + 2]);
  559.           else
  560.         {
  561.           if (!isint (argv[op + 1], &r))
  562.             integer_expected_error ("after -gt");
  563.         }
  564.           pos += 3;
  565.           return (TRUE == (l > r));
  566.         }
  567.  
  568.       if (argv[op][2] == 'e' && !argv[op][3])
  569.         {
  570.           /* ge - integer greater than or equal to */
  571.           if (l_is_l)
  572.         l = strlen (argv[op - 1]);
  573.           else
  574.         {
  575.           if (!isint (argv[op - 1], &l))
  576.             integer_expected_error ("before -ge");
  577.         }
  578.           if (r_is_l)
  579.         r = strlen (argv[op + 2]);
  580.           else
  581.         {
  582.           if (!isint (argv[op + 1], &r))
  583.             integer_expected_error ("after -ge");
  584.         }
  585.           pos += 3;
  586.           return (TRUE == (l >= r));
  587.         }
  588.       break;
  589.  
  590.     case 'n':
  591.       if (argv[op][2] == 't' && !argv[op][3])
  592.         {
  593.           /* nt - newer than */
  594.           pos += 3;
  595.           if (l_is_l || r_is_l)
  596.         test_syntax_error ("-nt does not accept -l\n", (char *)NULL);
  597.           if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r))
  598.         return (TRUE == (l > r));
  599.           else
  600.         return (FALSE);
  601.         }
  602.  
  603.       if (argv[op][2] == 'e' && !argv[op][3])
  604.         {
  605.           /* ne - integer not equal */
  606.           if (l_is_l)
  607.         l = strlen (argv[op - 1]);
  608.           else
  609.         {
  610.           if (!isint (argv[op - 1], &l))
  611.             integer_expected_error ("before -ne");
  612.         }
  613.           if (r_is_l)
  614.         r = strlen (argv[op + 2]);
  615.           else
  616.         {
  617.           if (!isint (argv[op + 1], &r))
  618.             integer_expected_error ("after -ne");
  619.         }
  620.           pos += 3;
  621.           return (TRUE == (l != r));
  622.         }
  623.       break;
  624.  
  625.     case 'e':
  626.       if (argv[op][2] == 'q' && !argv[op][3])
  627.         {
  628.           /* eq - integer equal */
  629.           if (l_is_l)
  630.         l = strlen (argv[op - 1]);
  631.           else
  632.         {
  633.           if (!isint (argv[op - 1], &l))
  634.             integer_expected_error ("before -eq");
  635.         }
  636.           if (r_is_l)
  637.         r = strlen (argv[op + 2]);
  638.           else
  639.         {
  640.           if (!isint (argv[op + 1], &r))
  641.             integer_expected_error ("after -eq");
  642.         }
  643.           pos += 3;
  644.           return (TRUE == (l == r));
  645.         }
  646.  
  647.       if (argv[op][2] == 'f' && !argv[op][3])
  648.         {
  649.           /* ef - hard link? */
  650.           pos += 3;
  651.           if (l_is_l || r_is_l)
  652.         test_syntax_error ("-ef does not accept -l\n", (char *)NULL);
  653.           if (stat (argv[op - 1], &stat_buf) < 0)
  654.         return (FALSE);
  655.           if (stat (argv[op + 1], &stat_spare) < 0)
  656.         return (FALSE);
  657.           return (TRUE ==
  658.               (stat_buf.st_dev == stat_spare.st_dev &&
  659.                stat_buf.st_ino == stat_spare.st_ino));
  660.         }
  661.       break;
  662.  
  663.     case 'o':
  664.       if ('t' == argv[op][2] && '\000' == argv[op][3])
  665.         {
  666.           /* ot - older than */
  667.           pos += 3;
  668.           if (l_is_l || r_is_l)
  669.         test_syntax_error ("-nt does not accept -l\n", (char *)NULL);
  670.           if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r))
  671.         return (TRUE == (l < r));
  672.           return (FALSE);
  673.         }
  674.       break;
  675.     }
  676.       test_syntax_error ("unknown binary operator", argv[op]);
  677.     }
  678.  
  679.   if (argv[op][0] == '=' && !argv[op][1])
  680.     {
  681.       value = (strcmp (argv[pos], argv[pos + 2]) == 0);
  682.       pos += 3;
  683.       return (TRUE == value);
  684.     }
  685.  
  686.   if (strcmp (argv[op], "!=") == 0)
  687.     {
  688.       value = (strcmp (argv[pos], argv[pos + 2]) != 0);
  689.       pos += 3;
  690.       return (TRUE == value);
  691.     }
  692. }
  693.  
  694. static int
  695. unary_operator ()
  696. {
  697.   long r, value;
  698.   struct stat stat_buf;
  699.  
  700.   switch (argv[pos][1])
  701.     {
  702.     default:
  703.       return (FALSE);
  704.  
  705.       /* All of the following unary operators use unary_advance (), which
  706.      checks to make sure that there is an argument, and then advances
  707.      pos right past it.  This means that pos - 1 is the location of the
  708.      argument. */
  709.  
  710.     case 'a':            /* file exists in the file system? */
  711.     case 'e':
  712.       unary_advance ();
  713.       value = -1 != test_stat (argv[pos - 1], &stat_buf);
  714.       return (TRUE == value);
  715.  
  716.     case 'r':            /* file is readable? */
  717.       unary_advance ();
  718.       value = -1 != eaccess (argv[pos - 1], R_OK);
  719.       return (TRUE == value);
  720.  
  721.     case 'w':            /* File is writeable? */
  722.       unary_advance ();
  723.       value = -1 != eaccess (argv[pos - 1], W_OK);
  724.       return (TRUE == value);
  725.  
  726.     case 'x':            /* File is executable? */
  727.       unary_advance ();
  728.       value = -1 != eaccess (argv[pos - 1], X_OK);
  729.       return (TRUE == value);
  730.  
  731.     case 'O':            /* File is owned by you? */
  732.       unary_advance ();
  733.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  734.     return (FALSE);
  735.  
  736.       return (TRUE == (geteuid () == stat_buf.st_uid));
  737.  
  738.     case 'G':            /* File is owned by your group? */
  739.       unary_advance ();
  740.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  741.     return (FALSE);
  742.  
  743.       return (TRUE == (getegid () == stat_buf.st_gid));
  744.  
  745.     case 'f':            /* File is a file? */
  746.       unary_advance ();
  747.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  748.     return (FALSE);
  749.  
  750.       /* Under POSIX, -f is true if the given file exists
  751.      and is a regular file. */
  752.       return (TRUE == ((S_ISREG (stat_buf.st_mode)) ||
  753.                (0 == (stat_buf.st_mode & S_IFMT))));
  754.  
  755.     case 'd':            /* File is a directory? */
  756.       unary_advance ();
  757.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  758.     return (FALSE);
  759.  
  760.       return (TRUE == (S_ISDIR (stat_buf.st_mode)));
  761.  
  762.     case 's':            /* File has something in it? */
  763.       unary_advance ();
  764.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  765.     return (FALSE);
  766.  
  767.       return (TRUE == (stat_buf.st_size > (off_t) 0));
  768.  
  769.     case 'S':            /* File is a socket? */
  770. #if !defined (S_ISSOCK)
  771.       return (FALSE);
  772. #else
  773.       unary_advance ();
  774.  
  775.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  776.     return (FALSE);
  777.  
  778.       return (TRUE == (S_ISSOCK (stat_buf.st_mode)));
  779. #endif                /* S_ISSOCK */
  780.  
  781.     case 'c':            /* File is character special? */
  782.       unary_advance ();
  783.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  784.     return (FALSE);
  785.  
  786.       return (TRUE == (S_ISCHR (stat_buf.st_mode)));
  787.  
  788.     case 'b':            /* File is block special? */
  789.       unary_advance ();
  790.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  791.     return (FALSE);
  792.  
  793.       return (TRUE == (S_ISBLK (stat_buf.st_mode)));
  794.  
  795.     case 'p':            /* File is a named pipe? */
  796.       unary_advance ();
  797. #ifndef S_ISFIFO
  798.       return (FALSE);
  799. #else
  800.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  801.     return (FALSE);
  802.       return (TRUE == (S_ISFIFO (stat_buf.st_mode)));
  803. #endif                /* S_ISFIFO */
  804.  
  805.     case 'L':            /* Same as -h  */
  806.       /*FALLTHROUGH*/
  807.  
  808.     case 'h':            /* File is a symbolic link? */
  809.       unary_advance ();
  810. #ifndef S_ISLNK
  811.       return (FALSE);
  812. #else
  813.       /* An empty filename is not a valid pathname. */
  814.       if ((argv[pos - 1][0] == '\0') ||
  815.       (lstat (argv[pos - 1], &stat_buf) < 0))
  816.     return (FALSE);
  817.  
  818.       return (TRUE == (S_ISLNK (stat_buf.st_mode)));
  819. #endif                /* S_IFLNK */
  820.  
  821.     case 'u':            /* File is setuid? */
  822.       unary_advance ();
  823.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  824.     return (FALSE);
  825.  
  826.       return (TRUE == (0 != (stat_buf.st_mode & S_ISUID)));
  827.  
  828.     case 'g':            /* File is setgid? */
  829.       unary_advance ();
  830.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  831.     return (FALSE);
  832.  
  833.       return (TRUE == (0 != (stat_buf.st_mode & S_ISGID)));
  834.  
  835.     case 'k':            /* File has sticky bit set? */
  836.       unary_advance ();
  837.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  838.     return (FALSE);
  839. #if !defined (S_ISVTX)
  840.       /* This is not Posix, and is not defined on some Posix systems. */
  841.       return (FALSE);
  842. #else
  843.       return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX)));
  844. #endif
  845.  
  846.     case 't':    /* File (fd) is a terminal?  (fd) defaults to stdout. */
  847.       advance (0);
  848.       if (pos < argc && isint (argv[pos], &r))
  849.     {
  850.       advance (0);
  851.       return (TRUE == (isatty ((int) r)));
  852.     }
  853.       return (TRUE == (isatty (1)));
  854.  
  855.     case 'n':            /* True if arg has some length. */
  856.       unary_advance ();
  857.       return (TRUE == (argv[pos - 1][0] != 0));
  858.  
  859.     case 'z':            /* True if arg has no length. */
  860.       unary_advance ();
  861.       return (TRUE == (argv[pos - 1][0] == '\0'));
  862.     }
  863. }
  864.     
  865. /*
  866.  * and:
  867.  *    term
  868.  *    term '-a' and
  869.  */
  870. static int
  871. and ()
  872. {
  873.   int value;
  874.  
  875.   value = term ();
  876.   while ((pos < argc) && strcmp (argv[pos], "-a") == 0)
  877.     {
  878.       advance (0);
  879.       value = TRUTH_AND (value, and ());
  880.     }
  881.   return (TRUE == value);
  882. }
  883.  
  884. /*
  885.  * or:
  886.  *    and
  887.  *    and '-o' or
  888.  */
  889. static int
  890. or ()
  891. {
  892.   int value;
  893.  
  894.   value = and ();
  895.  
  896.   while ((pos < argc) && strcmp (argv[pos], "-o") == 0)
  897.     {
  898.       advance (0);
  899.       value = TRUTH_OR (value, or ());
  900.     }
  901.  
  902.   return (TRUE == value);
  903. }
  904.  
  905. /*
  906.  * expr:
  907.  *    or
  908.  */
  909. static int
  910. expr ()
  911. {
  912.   if (pos >= argc)
  913.     beyond ();
  914.  
  915.   return (FALSE ^ (or ()));        /* Same with this. */
  916. }
  917.  
  918. /* Return TRUE if S is one of the test command's binary operators. */
  919. static int
  920. binop (s)
  921.      char *s;
  922. {
  923.   return ((STREQ (s,   "=")) || (STREQ (s,  "!=")) || (STREQ (s, "-nt")) ||
  924.       (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) ||
  925.       (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) ||
  926.       (STREQ (s, "-gt")) || (STREQ (s, "-ge")));
  927. }
  928.  
  929. /* Return non-zero if OP is one of the test command's unary operators. */
  930. static int
  931. unop (op)
  932.      int op;
  933. {
  934.   return (member (op, "abcdefgkLhprsStuwxOGnz"));
  935. }
  936.  
  937. static int
  938. two_arguments ()
  939. {
  940.   int value;
  941.  
  942.   if (STREQ (argv[pos], "!"))
  943.     value = strlen (argv[pos + 1]) == 0;
  944.   else if ((argv[pos][0] == '-') && (argv[pos][2] == '\0'))
  945.     {
  946.       if (unop (argv[pos][1]))
  947.     value = unary_operator ();
  948.       else
  949.     test_syntax_error ("%s: unary operator expected\n", argv[pos]);
  950.     }
  951.   else
  952.     beyond ();
  953.   return (value);
  954. }
  955.  
  956. static int
  957. three_arguments ()
  958. {
  959.   int value;
  960.  
  961.   if (STREQ (argv[pos], "!"))
  962.     {
  963.       advance (1);
  964.       value = !two_arguments ();
  965.     }
  966.   else if (binop (argv[pos+1]))
  967.     {
  968.       value = binary_operator ();
  969.       pos = argc;
  970.     }
  971.   else if ((STREQ (argv[pos+1], "-a")) || (STREQ (argv[pos+1], "-o")) ||
  972.        (argv[pos][0] == '('))
  973.     value = expr ();
  974.   else
  975.     test_syntax_error ("%s: binary operator expected\n", argv[pos+1]);
  976.   return (value);
  977. }
  978.  
  979. /* This is an implementation of a Posix.2 proposal by David Korn. */
  980. static int
  981. posixtest ()
  982. {
  983.   int value;
  984.  
  985.   switch (argc - 1)    /* one extra passed in */
  986.     {
  987.       case 0:
  988.     value = FALSE;
  989.     pos = argc;
  990.     break;
  991.  
  992.       case 1:
  993.     value = strlen (argv[1]) != 0;
  994.     pos = argc;
  995.     break;
  996.  
  997.       case 2:
  998.     value = two_arguments ();
  999.     pos = argc;
  1000.     break;
  1001.  
  1002.       case 3:
  1003.     value = three_arguments ();
  1004.     break;
  1005.  
  1006.       case 4:
  1007.     if (STREQ (argv[pos], "!"))
  1008.       {
  1009.         advance (1);
  1010.         value = !three_arguments ();
  1011.         break;
  1012.       }
  1013.     /* FALLTHROUGH */
  1014.       case 5:
  1015.       default:
  1016.     value = expr ();
  1017.     }
  1018.  
  1019.   return (value);
  1020. }
  1021.  
  1022. /*
  1023.  * [:
  1024.  *    '[' expr ']'
  1025.  * test:
  1026.  *    test expr
  1027.  */
  1028. int
  1029. #if defined (STANDALONE)
  1030. main (margc, margv)
  1031. #else
  1032. test_command (margc, margv)
  1033. #endif /* STANDALONE */
  1034.      int margc;
  1035.      char **margv;
  1036. {
  1037.   auto int value;
  1038.   int expr ();
  1039.  
  1040. #if !defined (STANDALONE)
  1041.   int code;
  1042.  
  1043.   code = setjmp (test_exit_buf);
  1044.  
  1045.   if (code)
  1046.     return (test_error_return);
  1047. #endif /* STANDALONE */
  1048.  
  1049.   argv = margv;
  1050.  
  1051.   if (margv[0] && strcmp (margv[0], "[") == 0)
  1052.     {
  1053.       --margc;
  1054.  
  1055.       if (margc < 2)
  1056.     test_exit (SHELL_BOOLEAN (FALSE));
  1057.  
  1058.       if (margv[margc] && strcmp (margv[margc], "]") != 0)
  1059.     test_syntax_error ("missing `]'\n", (char *)NULL);
  1060.     }
  1061.  
  1062.   argc = margc;
  1063.   pos = 1;
  1064.  
  1065.   if (pos >= argc)
  1066.     test_exit (SHELL_BOOLEAN (FALSE));
  1067.  
  1068.   value = posixtest ();
  1069.  
  1070.   if (pos != argc)
  1071.     test_syntax_error ("too many arguments\n", (char *)NULL);
  1072.  
  1073.   test_exit (SHELL_BOOLEAN (value));
  1074. }
  1075. @
  1076.  
  1077.  
  1078. 1.1
  1079. log
  1080. @Initial revision
  1081. @
  1082. text
  1083. @d73 1
  1084. a73 1
  1085. #if !defined (_POSIX_VERSION)
  1086. @
  1087.